using System;
using System.Collections.Generic;
using System.Text;
using OracleInternal.Common;
using OracleInternal.ServiceObjects;

namespace OracleInternal.TTC.Accessors
{
	internal class TTCRowIdAccessor : Accessor
	{
		private enum RowIdType
		{
			ROWID,
			UROWID
		}

		private RowIdType m_rowidType;

		private int[] m_temp = new int[1];

		internal const int ROWID_MAX_LENGTH = 128;

		internal const int KGRD_RESTRICTED_BLOCK = 8;

		internal const int KGRD_RESTRICTED_FILE = 4;

		internal const int KGRD_RESTRICTED_SLOT = 4;

		internal const int KGRD_EXTENDED_OBJECT = 6;

		internal const int KGRD_EXTENDED_BLOCK = 6;

		internal const int KGRD_EXTENDED_FILE = 3;

		internal const int KGRD_EXTENDED_SLOT = 3;

		internal const int KD4_UBRIDLEN_TYPEIND = 1;

		internal const int KD4_UBRIDLEN_PHYSOBJD = 4;

		internal const int KD4_UBRIDLEN_PHYSFNO = 2;

		internal const int KD4_UBRIDLEN_PHYSBNO = 4;

		internal const int KD4_UBRIDLEN_PHYSSNO = 2;

		internal const int FILENUMBEROFFSET = 5;

		internal const int BLOCKNUMBEROFFSET = 7;

		internal const int SLOTNUMBEROFFSET = 11;

		internal const ushort physicalRowID = 1;

		internal const int typeOfRowIdIndex = 0;

		internal static byte[] KGRD_BASIS_64 = new byte[64]
		{
			65,
			66,
			67,
			68,
			69,
			70,
			71,
			72,
			73,
			74,
			75,
			76,
			77,
			78,
			79,
			80,
			81,
			82,
			83,
			84,
			85,
			86,
			87,
			88,
			89,
			90,
			97,
			98,
			99,
			100,
			101,
			102,
			103,
			104,
			105,
			106,
			107,
			108,
			109,
			110,
			111,
			112,
			113,
			114,
			115,
			116,
			117,
			118,
			119,
			120,
			121,
			122,
			48,
			49,
			50,
			51,
			52,
			53,
			54,
			55,
			56,
			57,
			43,
			47
		};

		internal static byte[] KGRD_INDBYTE_CHAR = new byte[5]
		{
			65,
			42,
			45,
			40,
			41
		};

		internal static sbyte[] KGRD_INDEX_64 = new sbyte[128]
		{
			-1,
			-1,
			-1,
			-1,
			-1,
			-1,
			-1,
			-1,
			-1,
			-1,
			-1,
			-1,
			-1,
			-1,
			-1,
			-1,
			-1,
			-1,
			-1,
			-1,
			-1,
			-1,
			-1,
			-1,
			-1,
			-1,
			-1,
			-1,
			-1,
			-1,
			-1,
			-1,
			-1,
			-1,
			-1,
			-1,
			-1,
			-1,
			-1,
			-1,
			-1,
			-1,
			-1,
			62,
			-1,
			-1,
			-1,
			63,
			52,
			53,
			54,
			55,
			56,
			57,
			58,
			59,
			60,
			61,
			-1,
			-1,
			-1,
			-1,
			-1,
			-1,
			-1,
			0,
			1,
			2,
			3,
			4,
			5,
			6,
			7,
			8,
			9,
			10,
			11,
			12,
			13,
			14,
			15,
			16,
			17,
			18,
			19,
			20,
			21,
			22,
			23,
			24,
			25,
			-1,
			-1,
			-1,
			-1,
			-1,
			-1,
			26,
			27,
			28,
			29,
			30,
			31,
			32,
			33,
			34,
			35,
			36,
			37,
			38,
			39,
			40,
			41,
			42,
			43,
			44,
			45,
			46,
			47,
			48,
			49,
			50,
			51,
			-1,
			-1,
			-1,
			-1,
			-1
		};

		internal TTCRowIdAccessor(ColumnDescribeInfo colMetaData, MarshallingEngine marshallingEngine, bool bForBind)
			: base(colMetaData, marshallingEngine, bForBind)
		{
			if (m_internalType == OraType.ORA_UROWID)
			{
				m_rowidType = RowIdType.UROWID;
			}
			if (!bForBind)
			{
				InitForDataAccess(colMetaData.m_maxLength);
			}
		}

		internal override void InitForDataAccess(int max_len)
		{
			if (m_rowidType == RowIdType.ROWID)
			{
				m_internalTypeMaxLength = 128;
				if (max_len > 0 && max_len < m_internalTypeMaxLength)
				{
					m_internalTypeMaxLength = max_len;
				}
			}
			m_byteLength = m_internalTypeMaxLength;
		}

		internal override void UnmarshalColumnData()
		{
			if (!m_bNullByDescribe)
			{
				try
				{
					m_marshallingEngine.m_oraBufRdr.m_bParsingColumnData = true;
					m_marshallingEngine.m_oraBufRdr.m_bMarkStartOffsetForColData = true;
					if (m_rowidType == RowIdType.ROWID)
					{
						if (m_marshallingEngine.UnmarshalUB1() > 0)
						{
							m_marshallingEngine.UnmarshalUB4();
							m_marshallingEngine.UnmarshalUB2();
							m_marshallingEngine.UnmarshalUB1();
							m_marshallingEngine.UnmarshalUB4();
							m_marshallingEngine.UnmarshalUB2();
						}
						else
						{
							m_marshallingEngine.m_oraBufRdr.m_colDataStartOffset[m_marshallingEngine.m_oraBufRdr.m_colDataStartOffsetIndexToUpdate] = -1;
						}
					}
					else
					{
						long num = m_marshallingEngine.UnmarshalUB4();
						if (num > 0)
						{
							m_marshallingEngine.UnmarshalCLR_ColData((int)num);
						}
						else
						{
							m_marshallingEngine.m_oraBufRdr.m_colDataStartOffset[m_marshallingEngine.m_oraBufRdr.m_colDataStartOffsetIndexToUpdate] = -1;
						}
					}
				}
				finally
				{
					m_marshallingEngine.m_oraBufRdr.m_bParsingColumnData = false;
					m_marshallingEngine.m_oraBufRdr.m_bMarkStartOffsetForColData = false;
				}
			}
			m_lastRowProcessed++;
		}

		internal override bool UnmarshalOneRow()
		{
			List<ArraySegment<byte>> list = null;
			int num = 0;
			bool flag = false;
			if (!m_bNullByDescribe)
			{
				try
				{
					flag = m_marshallingEngine.m_oraBufRdr.StartAccumulatingColumnData(m_RowDataSegments, m_lastRowProcessed);
					if (m_rowidType == RowIdType.ROWID)
					{
						if (m_marshallingEngine.UnmarshalUB1() > 0)
						{
							long num2 = m_marshallingEngine.UnmarshalUB4();
							int num3 = m_marshallingEngine.UnmarshalUB2();
							short num4 = m_marshallingEngine.UnmarshalUB1();
							long num5 = m_marshallingEngine.UnmarshalUB4();
							int num6 = m_marshallingEngine.UnmarshalUB2();
							if (num2 != 0L || num3 != 0 || num4 != 0 || num5 != 0L || num6 != 0)
							{
								byte[] array = ROWIDToByteArray(num2, num3, num5, num6);
								int num7 = m_byteLength - 2;
								if (num7 > 18)
								{
									num7 = 18;
								}
								list = new List<ArraySegment<byte>>(1)
								{
									new ArraySegment<byte>(array, 0, num7)
								};
								num = num7;
							}
						}
					}
					else
					{
						long num8 = m_marshallingEngine.UnmarshalUB4();
						if (num8 > 0)
						{
							byte[] array2 = new byte[num8];
							m_marshallingEngine.UnmarshalCLR(array2, 0, m_temp);
							byte[] array3 = null;
							array3 = ((array2[0] != 1) ? LogicalROWIDToByteArray(array2) : PhysicalROWIDToByteArray(array2));
							int num9 = ((array3 != null) ? array3.Length : 0);
							list = new List<ArraySegment<byte>>(1)
							{
								new ArraySegment<byte>(array3, 0, num9)
							};
							num = num9;
						}
					}
				}
				finally
				{
					m_marshallingEngine.m_oraBufRdr.StopAccumulatingColumnData();
					if (m_bForBind && -1 == m_marshallingEngine.ProcessIndicator(num <= 0, num))
					{
						num = 0;
					}
				}
			}
			if (flag)
			{
				m_RowDataSegments.Add(list);
				m_totalLengthOfData.Add(num);
			}
			else
			{
				m_RowDataSegments[m_lastRowProcessed] = list;
				m_totalLengthOfData[m_lastRowProcessed] = num;
			}
			m_lastRowProcessed++;
			return false;
		}

		private byte[] ROWIDToByteArray(long rba, long partitionID, long blockNumber, long slotNumber)
		{
			byte[] array = new byte[18];
			int offset = 0;
			offset = kgrd42b(array, rba, 6, offset);
			offset = kgrd42b(array, partitionID, 3, offset);
			offset = kgrd42b(array, blockNumber, 6, offset);
			offset = kgrd42b(array, slotNumber, 3, offset);
			return array;
		}

		private int kgrd42b(byte[] charsAsBytes, long value, int size, int offset)
		{
			int num = size;
			long num2 = value;
			while (size > 0)
			{
				charsAsBytes[offset + size - 1] = KGRD_BASIS_64[(int)num2 & 0x3F];
				num2 = HelperClass.URShift(num2, 6);
				size--;
			}
			return num + offset;
		}

		private byte[] PhysicalROWIDToByteArray(byte[] byteStream)
		{
			byte[] array = new byte[18];
			riddef rowId = default(riddef);
			PopulateRowIdStructFromByteStream(byteStream, ref rowId);
			if (rowId.ridobjnum == 0)
			{
				ConvertToRestrictedFormat(rowId, array);
			}
			else
			{
				ConvertToExtendedFormat(rowId, array);
			}
			return array;
		}

		private void ConvertToExtendedFormat(riddef ridRowID, byte[] byteArray)
		{
			int offset = 0;
			uint ridobjnum = ridRowID.ridobjnum;
			offset = kgrd42b(byteArray, ridobjnum, 6, offset);
			ridobjnum = ridRowID.idfilenum;
			offset = kgrd42b(byteArray, ridobjnum, 3, offset);
			ridobjnum = ridRowID.ridblocknum;
			offset = kgrd42b(byteArray, ridobjnum, 6, offset);
			ridobjnum = ridRowID.ridslotnum;
			offset = kgrd42b(byteArray, ridobjnum, 3, offset);
		}

		private byte[] LogicalROWIDToByteArray(byte[] byteStream)
		{
			byte[] array = null;
			int num = byteStream.Length;
			int num2 = num / 3;
			int num3 = 4 * num2 + (num % 3) switch
			{
				1 => 1, 
				0 => 0, 
				_ => 3, 
			};
			if (num3 > 0)
			{
				array = new byte[num3];
				kgrdub2c(byteStream, num, 0, array, 0);
			}
			return array;
		}

		private void PopulateRowIdStructFromByteStream(byte[] bytes, ref riddef rowId)
		{
			rowId.ridobjnum = Get4Bytes(bytes, 1);
			rowId.idfilenum = Get2Bytes(bytes, 5);
			rowId.filler = 0;
			rowId.ridblocknum = Get4Bytes(bytes, 7);
			rowId.ridslotnum = Get2Bytes(bytes, 11);
		}

		private ushort Get2Bytes(byte[] bytes, int offset)
		{
			return (ushort)((bytes[offset] << 8) + bytes[offset + 1]);
		}

		private uint Get4Bytes(byte[] bytes, int offset)
		{
			return (uint)((((bytes[offset] << 8) + bytes[offset + 1] << 8) + bytes[offset + 2] << 8) + bytes[offset + 3]);
		}

		private void ConvertToRestrictedFormat(riddef ridRowId, byte[] bytes)
		{
			char paddingChar = '0';
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.Append(Convert.ToString(ridRowId.ridblocknum, 16).PadLeft(8, paddingChar));
			stringBuilder.Append('.');
			stringBuilder.Append(Convert.ToString(ridRowId.ridslotnum, 16).PadLeft(4, paddingChar));
			stringBuilder.Append('.');
			stringBuilder.Append(Convert.ToString(ridRowId.idfilenum, 16).PadLeft(4, paddingChar));
			string text = stringBuilder.ToString().ToUpperInvariant();
			int num = 0;
			string text2 = text;
			foreach (char c in text2)
			{
				bytes[num++] = (byte)c;
			}
		}

		private void kgrdub2c(byte[] bytes, int size, int offset, byte[] dstBytes, int dstOffset)
		{
			dstBytes[dstOffset] = KGRD_INDBYTE_CHAR[bytes[offset] - 1];
			int num = size - 1;
			int num2 = offset + 1;
			int num3 = 1;
			byte b = 0;
			while (num > 0)
			{
				dstBytes[dstOffset + num3++] = KGRD_BASIS_64[(bytes[num2] & 0xFF) >> 2];
				if (num == 1)
				{
					dstBytes[dstOffset + num3++] = KGRD_BASIS_64[(bytes[num2] & 3) << 4];
					break;
				}
				b = (byte)(bytes[num2 + 1] & 0xFFu);
				dstBytes[dstOffset + num3++] = KGRD_BASIS_64[((bytes[num2] & 3) << 4) | ((b & 0xF0) >> 4)];
				if (num == 2)
				{
					dstBytes[dstOffset + num3++] = KGRD_BASIS_64[(b & 0xF) << 2];
					break;
				}
				num2 += 2;
				dstBytes[dstOffset + num3++] = KGRD_BASIS_64[((b & 0xF) << 2) | ((bytes[num2] & 0xC0) >> 6)];
				dstBytes[dstOffset + num3] = KGRD_BASIS_64[bytes[num2] & 0x3F];
				num -= 3;
				num2++;
				num3++;
			}
		}

		internal int UnmarshalHelper(DataUnmarshaller dataUnmarshaller, int currentRow, int columnIndex)
		{
			int length = 0;
			if (m_rowidType == RowIdType.ROWID)
			{
				if (dataUnmarshaller.UnmarshalUB1() > 0)
				{
					long num = dataUnmarshaller.UnmarshalUB4();
					int num2 = dataUnmarshaller.UnmarshalUB2();
					short num3 = dataUnmarshaller.UnmarshalUB1();
					long num4 = dataUnmarshaller.UnmarshalUB4();
					int num5 = dataUnmarshaller.UnmarshalUB2();
					if (num != 0L || num2 != 0 || num3 != 0 || num4 != 0L || num5 != 0)
					{
						byte[] array = ROWIDToByteArray(num, num2, num4, num5);
						int num6 = m_byteLength - 2;
						if (num6 > 18)
						{
							num6 = 18;
						}
						m_colDataSegments = new List<ArraySegment<byte>>(1)
						{
							new ArraySegment<byte>(array, 0, num6)
						};
						length = num6;
					}
				}
			}
			else
			{
				length = (int)dataUnmarshaller.UnmarshalUB4();
				if (length > 0)
				{
					byte[] array2 = new byte[length];
					dataUnmarshaller.UnmarshalCLR(length, array2, ref length);
					byte[] array3 = null;
					array3 = ((array2[0] != 1) ? LogicalROWIDToByteArray(array2) : PhysicalROWIDToByteArray(array2));
					int num7 = ((array3 != null) ? array3.Length : 0);
					m_colDataSegments.Add(new ArraySegment<byte>(array3, 0, num7));
					length = num7;
				}
			}
			return length;
		}

		internal override string GetString(DataUnmarshaller dataUnmarshaller, int currentRow, int columnIndex, byte charSetForm)
		{
			string result = null;
			try
			{
				dataUnmarshaller.StartAccumulatingColumnData(currentRow, columnIndex, m_colDataSegments);
				int num = UnmarshalHelper(dataUnmarshaller, currentRow, columnIndex);
				if (num > 0)
				{
					char[] charArrayForConversion = dataUnmarshaller.m_charArrayForConversion;
					if (charSetForm == 2)
					{
						return m_marshallingEngine.m_nCharSetConv.ConvertBytesToString(m_colDataSegments, 0, num, charArrayForConversion);
					}
					return m_marshallingEngine.m_dbCharSetConv.ConvertBytesToString(m_colDataSegments, 0, num, charArrayForConversion);
				}
				return result;
			}
			finally
			{
				m_colDataSegments.Clear();
				dataUnmarshaller.m_bAccumulateByteSegments = false;
				dataUnmarshaller.m_dataSegments = null;
			}
		}

		internal long GetChars(DataUnmarshaller dataUnmarshaller, int currentRow, int columnIndex, long fieldOffset, char[] buffer, int bufferOffset, int noOfCharsReqd)
		{
			int charCount = 0;
			try
			{
				dataUnmarshaller.StartAccumulatingColumnData(currentRow, columnIndex, m_colDataSegments);
				int num = UnmarshalHelper(dataUnmarshaller, currentRow, columnIndex);
				if (num > 0)
				{
					charCount = noOfCharsReqd;
					int bytesOffset = (int)fieldOffset;
					if (m_marshallingEngine.m_dbCharSetConv.MaxBytesPerChar > 1 && fieldOffset > 0)
					{
						bytesOffset = m_marshallingEngine.m_dbCharSetConv.GetBytesOffset(m_colDataSegments, (int)fieldOffset);
					}
					if (buffer != null)
					{
						m_marshallingEngine.m_dbCharSetConv.ConvertBytesToChars(m_colDataSegments, bytesOffset, num, buffer, bufferOffset, ref charCount);
					}
					else
					{
						charCount = m_marshallingEngine.m_dbCharSetConv.GetCharsLength(m_colDataSegments, bytesOffset, num);
					}
				}
			}
			finally
			{
				m_colDataSegments.Clear();
				dataUnmarshaller.m_bAccumulateByteSegments = false;
				dataUnmarshaller.m_dataSegments = null;
			}
			return charCount;
		}
	}
}
